package xcmg.device.service.order;


import cn.hutool.core.collection.CollectionUtil;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import xcmg.device.dao.entity.barcode.BarcodeManageDO;
import xcmg.device.dao.entity.order.GpsMmSwOrderLabelDO;
import xcmg.device.dao.entity.order.SubcontractingOrderDO;
import xcmg.device.dao.entity.order.SubcontractingOrderDetailDO;
import xcmg.device.dao.entity.warehouse.WarehouseInboundDO;
import xcmg.device.dao.entity.warehouse.WarehouseInboundDetailDO;
import xcmg.device.dao.mapper.BarcodeManageMapper;
import xcmg.device.dao.mapper.order.GpsMmSwOrderLabelMapper;
import xcmg.device.dao.mapper.order.SubcontractingOrderMapper;
import xcmg.device.dao.mapper.warehouse.WarehouseInboundDetailMapper;
import xcmg.device.dao.mapper.warehouse.WarehouseInboundMapper;
import xcmg.device.infra.ErrorCode;
import xcmg.device.infra.enums.BarcodeStatus;
import xcmg.device.infra.enums.BillDesc;
import xcmg.device.infra.exception.CommonBusiExceptions;
import xcmg.device.service.vo.order.SubcontractingOrderDetailVO;
import xcmg.device.service.vo.order.SubcontractingOrderVO;
import xcmg.device.service.vo.warehouse.DefaultWarehouseVO;
import xcmg.device.service.vo.warehouse.WarehouseInboundRecordAddVO;
import xcmg.device.service.warehouse.WarehouseCompose;
import xcmg.device.service.warehouse.WarehouseInboundRecordService;
import yb.ecp.fast.infra.infra.PageCommonVO;
import yb.ecp.fast.infra.infra.SearchCommonVO;
import yb.ecp.fast.infra.util.PageHelperPlus;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * SubcontractingOrder 后台接口实现类
 */
@Slf4j
@Service
public class SubcontractingOrderService {

    @Autowired
    private SubcontractingOrderMapper subcontractingOrderMapper;

    @Autowired
    private SubcontractingOrderDetailService subcontractingOrderDetailService;

    @Autowired
    private SubcontractingOrderAddService subcontractingOrderAddService;

    @Autowired
    private GpsMmSwOrderLabelService gpsMmSwOrderLabelService;

    @Autowired
    private WarehouseInboundRecordService warehouseInboundRecordService;

    @Autowired
    private BarcodeManageMapper barcodeManageMapper;

    @Autowired
    private WarehouseInboundMapper warehouseInboundMapper;

    @Autowired
    private WarehouseInboundDetailMapper warehouseInboundDetailMapper;

    @Autowired
    private GpsMmSwOrderLabelMapper gpsMmSwOrderLabelMapper;

    @Autowired
    private WarehouseCompose warehouseCompose;

    public PageCommonVO<SubcontractingOrderVO> list(SearchCommonVO<SubcontractingOrderVO> condition) {
        PageCommonVO<SubcontractingOrderVO> result = new PageCommonVO<>();
        PageHelperPlus.startPage(condition.getPageNum(), condition.getPageSize());
//                PageHelperPlus.orderBy("create_date desc");
        List<SubcontractingOrderVO> resultList = subcontractingOrderMapper.queryList(condition.getFilters());
        result.setPageInfo(new PageInfo(resultList));
        result.setPageInfoList(resultList);
        return result;
    }

    public SubcontractingOrderVO getDetailById(String id) {
        SubcontractingOrderVO r = getById(id);
        List<GpsMmSwOrderLabelDO> labels = gpsMmSwOrderLabelService.queryListByOrderId(r.getOrderId());
        r.setLabels(labels);
        return r;
    }

    public SubcontractingOrderVO getById(String id) {
        SubcontractingOrderVO r = null;
        SubcontractingOrderVO vo = new SubcontractingOrderVO();
        vo.setId(id);
        List<SubcontractingOrderVO> resultList = subcontractingOrderMapper.queryList(vo);
        if (null != resultList && resultList.size() > 0) {
            processDetail(resultList);
            r = resultList.get(0);
        }
        processZbAmount(r);
        return r;
    }

    public SubcontractingOrderVO getByCode(String code) {
        SubcontractingOrderVO r = null;
        SubcontractingOrderVO vo = new SubcontractingOrderVO();
        vo.setCode(code);
        List<SubcontractingOrderVO> resultList = subcontractingOrderMapper.queryList(vo);
        if (null != resultList && resultList.size() > 0) {
            processDetail(resultList);
            r = resultList.get(0);
        }
        return r;
    }

    private void processZbAmount(SubcontractingOrderVO r) {
        if (null != r && r.getState() == 0) {
            if (!CollectionUtils.isEmpty(r.getDetails())) {
                Map<String, SubcontractingOrderDetailVO> lam = subcontractingOrderDetailService.queryList4LabelAmountMap(r.getId());
                if (ObjectUtils.isNotEmpty(lam)) {
                    r.getDetails().forEach(detail -> {
                        SubcontractingOrderDetailVO la = lam.get(detail.getId());
                        if (null != la && null != la.getPackageNum()) {
                            detail.setZbAmount(BigDecimal.valueOf(la.getPackageNum()));
                        } else {
                            detail.setZbAmount(BigDecimal.ZERO);
                        }
                    });
                }
            }
        }
    }

    private void processDetail(List<SubcontractingOrderVO> resultList) {
        List<String> ids = resultList.stream().map(SubcontractingOrderVO::getId).collect(Collectors.toList());
        Map<String, List<SubcontractingOrderDetailVO>> map = subcontractingOrderDetailService.queryHeadMap(ids);
        resultList.forEach(vo -> {
            List<SubcontractingOrderDetailVO> detailList = map.get(vo.getId());
            vo.setDetails(detailList);
        });
    }

    public ErrorCode delete(String id, String userId) {
        SubcontractingOrderVO v = getById(id);
        if (null == v) {
            throw new CommonBusiExceptions("订单不存在");
        }
        if (v.getState() != 0) {
            throw new CommonBusiExceptions("订单状态异常,不可以删除");
        }
        subcontractingOrderMapper.deleteByPrimaryKeySelective(id);
        return ErrorCode.Success;
    }

    @Transactional
    public ErrorCode inStock(SubcontractingOrderVO p) {
        SubcontractingOrderVO v = getDetailById(p.getId());
        if (null == v) {
            throw new CommonBusiExceptions("订单不存在");
        }
        if (v.getState() != 0) {
            throw new CommonBusiExceptions("订单状态异常,不可以入库");
        }
        if (null == p.getWarehouseCode()) {
            throw new CommonBusiExceptions("请选择入库仓库");
        }
        v.setOrgId(p.getOrgId());
        v.setWarehouseCode(p.getWarehouseCode());
        //处理默认仓库库区储位
        processDefaultLocation(v);
        if (CollectionUtils.isEmpty(v.getDetails()) || CollectionUtils.isEmpty(v.getLabels())) {
            throw new CommonBusiExceptions("当前无条码明细等信息不满足入库条件");
        }
        //条码按照物料分组
        Map<String, List<GpsMmSwOrderLabelDO>> map = v.getLabels().stream().collect(Collectors.groupingBy(GpsMmSwOrderLabelDO::getPartNo));
        List<BarcodeManageDO> bars = new ArrayList<>();

        WarehouseInboundDO inbound = new WarehouseInboundDO();
        List<WarehouseInboundDetailDO> inboundDetailDOS = new ArrayList<>();
        // 收集条码、入库基表 数据
        collectInboundDatas(bars, inbound, inboundDetailDOS, v, p, map);

        SubcontractingOrderDO upOrder = new SubcontractingOrderDO();
        upOrder.setId(p.getId());
        upOrder.setWarehouseCode(p.getWarehouseCode());
        upOrder.setLocationCode(p.getLocationCode());
        upOrder.setAreaCode(p.getAreaCode());
        upOrder.setOrgId(p.getOrgId());
        subcontractingOrderMapper.updateNotNullByPrimaryKeySelective(upOrder);

        List<WarehouseInboundRecordAddVO> records = new ArrayList<>();
        bars.forEach(barcodeManageDO -> {
            WarehouseInboundRecordAddVO record = new WarehouseInboundRecordAddVO();
            record.setBarCode(barcodeManageDO.getBarcode());
            record.setBusinessOrder(v.getCode());
            record.setFrozen(0);
            record.setLocationCode(v.getLocationCode());
            record.setAmount(barcodeManageDO.getTotalQty());
            records.add(record);
            try {
                barcodeManageMapper.insert(barcodeManageDO);
            }catch (Exception e) {
                throw new CommonBusiExceptions("条码【" + barcodeManageDO.getBarcode() + "】保存失败");
            }
        });
        inboundDetailDOS.forEach(inboundDetailDO -> {
            warehouseInboundDetailMapper.insert(inboundDetailDO);
        });
        warehouseInboundMapper.insert(inbound);

        v.getLabels().forEach(labelDO -> {
            GpsMmSwOrderLabelDO updateLabelDO = new GpsMmSwOrderLabelDO();
            updateLabelDO.setId(labelDO.getId());
            updateLabelDO.setUseState(1);
            gpsMmSwOrderLabelMapper.updateNotNullByPrimaryKeySelective(updateLabelDO);
        });
        for (WarehouseInboundRecordAddVO record : records) {
            try {
                ErrorCode errorCode1 = warehouseInboundRecordService.add(record, p.getUpdateId(), p.getOrgId());
                if (errorCode1.getCode() != ErrorCode.Success.getCode()) {
                    throw new Exception("条码【" + record.getBarCode() + "】入库失败--" + errorCode1.getDesc());
                }
            } catch (Exception e) {
                log.error("条码【" + record.getBarCode() + "】入库失败", e);
                throw new CommonBusiExceptions("条码【" + record.getBarCode() + "】入库失败");
            }
        }
        return ErrorCode.Success;
    }

    private void processDefaultLocation(SubcontractingOrderVO v) {
        DefaultWarehouseVO w = warehouseCompose.queryDefaultWarehouseLocation(v.getOrgId(), v.getWarehouseCode());
        if (null != w && null != w.getLocationCode()) {
            v.setLocationCode(w.getLocationCode());
            v.setAreaCode(w.getAreaCode());
        } else {
            throw new CommonBusiExceptions("请维护仓库下默认储位");
        }
    }

    private void collectInboundDatas(List<BarcodeManageDO> bars, WarehouseInboundDO inbound,
                                     List<WarehouseInboundDetailDO> inboundDetailDOS, SubcontractingOrderVO v,
                                     SubcontractingOrderVO p, Map<String, List<GpsMmSwOrderLabelDO>> map) {
        Date now = new Date();
        BigDecimal totalAmount = BigDecimal.ZERO;
        for (SubcontractingOrderDetailVO detail : v.getDetails()) {
            List<GpsMmSwOrderLabelDO> l = map.get(detail.getComponentNo());
            if (ObjectUtils.isNotEmpty(l)) {
                BigDecimal amount = BigDecimal.ZERO;
                for (GpsMmSwOrderLabelDO labelDO : l) {
                    if (null != labelDO.getPackageNum() && labelDO.getPackageNum() > 0) {
                        amount = amount.add(BigDecimal.valueOf(labelDO.getPackageNum()));
                        BarcodeManageDO barcodeManageDO = new BarcodeManageDO();
                        barcodeManageDO.setBarcode(labelDO.getBarcode());
                        barcodeManageDO.setTotalBarcode(labelDO.getBarcode());
                        barcodeManageDO.setOrgId(p.getOrgId());
                        barcodeManageDO.setBillType(BillDesc.ZBD.getDesc());
                        barcodeManageDO.setBillId(v.getId());
                        barcodeManageDO.setBillNo(v.getCode());
                        barcodeManageDO.setBarcodeFlag(1);
                        barcodeManageDO.setMaterialsNo(labelDO.getPartNo());
                        barcodeManageDO.setMaterialsDes(labelDO.getPartNo());
                        barcodeManageDO.setTotalQty(BigDecimal.valueOf(labelDO.getPackageNum()));
                        barcodeManageDO.setCurrentQty(BigDecimal.valueOf(labelDO.getPackageNum()));
                        barcodeManageDO.setLeftQty(BigDecimal.valueOf(labelDO.getPackageNum()));
                        barcodeManageDO.setWarehouseCode(v.getWarehouseCode());
                        barcodeManageDO.setPrintId(v.getUpdateId());
                        barcodeManageDO.setPrintName(v.getUpdateName());
                        barcodeManageDO.setPrintTime(new Date());
                        barcodeManageDO.setReprintCount(0);
                        barcodeManageDO.setBarcodeStatus(BarcodeStatus.Status.Printed.toString());
//                        barcodeManageDO.setRowNo(labelDO.getOrderNoRow());
                        barcodeManageDO.setCreateId(v.getUpdateId());
                        barcodeManageDO.setCreateName(v.getUpdateName());
                        barcodeManageDO.setCreateTime(new Date());
                        barcodeManageDO.setIsDel(false);
                        barcodeManageDO.setIsSeparate(false);
                        barcodeManageDO.setSeq(0);
                        bars.add(barcodeManageDO);
                    }
                }
                totalAmount = totalAmount.add(amount);
                detail.setZbAmount(amount);
                WarehouseInboundDetailDO inboundDetailDO = new WarehouseInboundDetailDO();
                inboundDetailDO.setId(detail.getId());
                inboundDetailDO.setBusinessSingle(BillDesc.ZBD.getDesc());
                inboundDetailDO.setBusinessOrder(v.getCode());
                inboundDetailDO.setMaterialNo(detail.getComponentNo());
                inboundDetailDO.setMaterialName(detail.getMaterialsDes());
//                inboundDetailDO.setMaterialType(detail.getMaterialType());
                inboundDetailDO.setWarehouseCode(p.getWarehouseCode());
                inboundDetailDO.setAreaCode(p.getAreaCode());
                inboundDetailDO.setLocationCode(p.getLocationCode());
                inboundDetailDO.setAmount(amount);
                inboundDetailDO.setRealAmount(detail.getRealAmount());
//                inboundDetailDO.setUnit(detail.getUnit());
//                inboundDetailDO.setModel(detail.getModel());
//                inboundDetailDO.setNote(detail.getNote());
                inboundDetailDO.setStatus(0);
                inboundDetailDO.setCreaterId(p.getUpdateId());
                inboundDetailDO.setCreaterName(p.getUpdateName());
                inboundDetailDO.setCreateDate(now);
//                inboundDetailDO.setSapOprType(detail.getSapOprType());
                inboundDetailDO.setOrgId(p.getOrgId());
//                inboundDetailDO.setKeepName(detail.getKeepName());
                inboundDetailDO.setInboundOrder(v.getCode());
//                inboundDetailDO.setTotalPrice(detail.getTotalPrice());
                inboundDetailDO.setPrintNum(amount);
                inboundDetailDO.setPrintState(0);
//                inboundDetailDO.setDeliveryInstructionNo(detail.getDeliveryInstructionNo());
//                inboundDetailDO.setRowNo(detail.getRowNo());
                inboundDetailDOS.add(inboundDetailDO);
            }
        }

        inbound.setId(v.getId());
        inbound.setBusinessSingle(BillDesc.ZBD.getDesc());
        inbound.setBusinessOrder(v.getCode());
        inbound.setWarehouseCode(v.getWarehouseCode());
        inbound.setAmount(totalAmount);
        inbound.setStatus(0);
//        inbound.setNote(v.getNote());
        inbound.setCreaterId(v.getUpdateId());
        inbound.setCreaterName(v.getUpdateName());
        inbound.setCreateDate(now);
        inbound.setOrgId(p.getOrgId());
        inbound.setInboundOrder(v.getCode());
        inbound.setSupplier(v.getSupplierName());
//        inbound.setTotalPrice(v.getTotalPrice());
//        inbound.setSplitOrder(v.getSplitOrder());
//        inbound.setSapOrder(v.getSapOrder());
//        inbound.setVoucherNo(v.getVoucherNo());
        inbound.setInvalidFlag(0);
        inbound.setInArea(p.getAreaCode());
//        inbound.setOutArea(v.getOutArea());
    }

    public void createZbdByBarcode(List<GpsMmSwOrderLabelDO> ll) {
        List<Long> orderIds = ll.stream().map(GpsMmSwOrderLabelDO::getOrderId).distinct().sorted().collect(Collectors.toList());
        for (Long orderId : orderIds) {
            try {
                subcontractingOrderAddService.createZbdByBarcode(orderId);
            } catch (Exception e) {
                log.error("根据订单 orderId：{} 生成转包单异常", orderId, e);
            }
        }
    }

    public boolean updateByInbound(String code, String materialNo, BigDecimal realAmount, Integer singleState,
                                   Integer totalState, String orgId, BigDecimal amount) {
        SubcontractingOrderVO m = getByCode(code);
        if (m == null && !CollectionUtil.isEmpty(m.getDetails())) {
            return false;
        }
        Date now = new Date();
        for (SubcontractingOrderDetailVO detail : m.getDetails()) {
            if (detail.getComponentNo().equals(materialNo)) {
                SubcontractingOrderDetailDO inboundDetailDO = new SubcontractingOrderDetailDO();
                inboundDetailDO.setId(detail.getId());
                inboundDetailDO.setRealAmount(realAmount);
                inboundDetailDO.setZbAmount(realAmount);
                subcontractingOrderDetailService.updateNotNullByPrimaryKeySelective(inboundDetailDO);
            }
        }
        SubcontractingOrderDO inbound = new SubcontractingOrderDO();
        inbound.setId(m.getId());
        inbound.setState(totalState);
        inbound.setInTime(now);
        inbound.setUpdatedTime(now);
        return subcontractingOrderMapper.updateNotNullByPrimaryKeySelective(inbound) > 0;
    }

    public void updateById(SubcontractingOrderDO sod) {
        subcontractingOrderMapper.updateNotNullByPrimaryKeySelective(sod);
    }
}
